#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#include <direct.h>  // 用于创建目录
#include <time.h>    // 用于计时

// 从DLL生成的头文件中引入定义
#include "unzip.h"

// 函数指针类型定义（与DLL导出函数匹配）
typedef UnzipErrCode (*PFN_UnzipFile)(char*, char*);
typedef UnzipErrCode (*PFN_UnzipFileWithFormat)(char*, char*, UnzipFormat);
typedef char* (*PFN_UnzipGetLastError)();

// 全局函数指针
PFN_UnzipFile pUnzipFile = NULL;
PFN_UnzipFileWithFormat pUnzipFileWithFormat = NULL;
PFN_UnzipGetLastError pUnzipGetLastError = NULL;
HMODULE hDLL = NULL;

// 格式名称映射表，与UnzipFormat枚举对应
const char* formatNames[] = {
    "自动识别",    // 0: UNZIP_FORMAT_AUTO
    "ZIP",         // 1: UNZIP_FORMAT_ZIP
    "TAR",         // 2: UNZIP_FORMAT_TAR
    "TAR.GZ/TGZ",  // 3: UNZIP_FORMAT_TAR_GZ
    "TAR.BZ2",     // 4: UNZIP_FORMAT_TAR_BZ2
    "TAR.XZ",      // 5: UNZIP_FORMAT_TAR_XZ
    "TAR.ZST",     // 6: UNZIP_FORMAT_TAR_ZST
    "7Z",          // 7: UNZIP_FORMAT_7Z
    "RAR",         // 8: UNZIP_FORMAT_RAR
    "GZ(单文件)",  // 9: UNZIP_FORMAT_GZ
    "BZ2(单文件)", // 10: UNZIP_FORMAT_BZ2
    "XZ(单文件)",  // 11: UNZIP_FORMAT_XZ
    "ZST(单文件)"  // 12: UNZIP_FORMAT_ZST
};

// 加载解压DLL
int loadUnzipDLL(const char* dllPath) {
    // 如果已经加载则先释放
    if (hDLL != NULL) {
        FreeLibrary(hDLL);
        hDLL = NULL;
    }

    // 加载DLL
    hDLL = LoadLibraryA(dllPath);
    if (hDLL == NULL) {
        fprintf(stderr, "错误：无法加载DLL文件 %s (错误码: %lu)\n", 
                dllPath, GetLastError());
        return -1;
    }

    // 获取函数指针
    pUnzipFile = (PFN_UnzipFile)GetProcAddress(hDLL, "UnzipFile");
    pUnzipFileWithFormat = (PFN_UnzipFileWithFormat)GetProcAddress(hDLL, "UnzipFileWithFormat");
    pUnzipGetLastError = (PFN_UnzipGetLastError)GetProcAddress(hDLL, "UnzipGetLastError");

    if (!pUnzipFile || !pUnzipFileWithFormat || !pUnzipGetLastError) {
        fprintf(stderr, "错误：无法获取DLL中的函数 (错误码: %lu)\n", GetLastError());
        FreeLibrary(hDLL);
        hDLL = NULL;
        return -1;
    }

    return 0;
}

// 释放DLL资源
void freeUnzipDLL() {
    if (hDLL != NULL) {
        FreeLibrary(hDLL);
        hDLL = NULL;
        pUnzipFile = NULL;
        pUnzipFileWithFormat = NULL;
        pUnzipGetLastError = NULL;
    }
}

// 检查文件是否存在
int fileExists(const char* path) {
    FILE* file = fopen(path, "r");
    if (file) {
        fclose(file);
        return 1;
    }
    return 0;
}

// 创建目录（支持多级目录）
int createDirectory(const char* path) {
    // 复制路径以避免修改原字符串
    char* dirPath = _strdup(path);
    if (!dirPath) return 0;

    int result = 1;
    char* p = dirPath;
    
    // 处理不同平台的路径分隔符
    while (*p) {
        if (*p == '\\' || *p == '/') {
            *p = '\0';
            // 创建当前子目录
            if (_mkdir(dirPath) != 0 && errno != EEXIST) {
                result = 0;
                break;
            }
            *p = '\\'; // 统一使用Windows风格分隔符
        }
        p++;
    }

    // 创建最后一级目录
    if (result && _mkdir(dirPath) != 0 && errno != EEXIST) {
        result = 0;
    }

    free(dirPath);
    return result;
}

// 打印错误信息
void printError(UnzipErrCode code) {
    const char* errMsg = pUnzipGetLastError();
    switch (code) {
        case UNZIP_OK:
            printf("操作成功\n");
            break;
        case UNZIP_ERR_OPEN_FILE:
            fprintf(stderr, "错误：打开文件失败 - %s\n", errMsg);
            break;
        case UNZIP_ERR_FORMAT:
            fprintf(stderr, "错误：格式不支持或识别失败 - %s\n", errMsg);
            break;
        case UNZIP_ERR_EXTRACT:
            fprintf(stderr, "错误：解压过程失败 - %s\n", errMsg);
            break;
        case UNZIP_ERR_MEM:
            fprintf(stderr, "错误：内存分配失败 - %s\n", errMsg);
            break;
        case UNZIP_ERR_PERM:
            fprintf(stderr, "错误：权限不足 - %s\n", errMsg);
            break;
        default:
            fprintf(stderr, "错误：未知错误 (代码: %d) - %s\n", code, errMsg);
    }
}

// 打印格式列表
void printFormatList() {
    printf("\n支持的压缩格式列表：\n");
    printf("  0: %s\n", formatNames[0]);
    for (int i = 1; i < sizeof(formatNames)/sizeof(formatNames[0]); i++) {
        printf("  %d: %s\n", i, formatNames[i]);
    }
    printf("\n");
}

// 打印帮助信息
void printHelp(const char* progName) {
    printf("通用压缩包解压工具 v1.0\n");
    printf("支持格式：ZIP, 7Z, RAR, TAR, TAR.GZ, TAR.BZ2, TAR.XZ, TAR.ZST, GZ, BZ2, XZ, ZST\n");
    printf("用法：%s [选项] <压缩文件路径> <输出目录>\n", progName);
    printf("选项：\n");
    printf("  -f <格式编号>  指定压缩格式（默认自动识别，格式编号见下方列表）\n");
    printf("  -l            显示支持的压缩格式列表\n");
    printf("  -h            显示本帮助信息\n");
    printFormatList();
    printf("示例：\n");
    printf("  %s archive.zip ./output\n", progName);
    printf("  %s -f 7 data.7z ./7z_output\n", progName);
}

// 主函数
int main(int argc, char* argv[]) {
    const char* inputFile = NULL;
    const char* outputDir = NULL;
    UnzipFormat format = UNZIP_FORMAT_AUTO;
    int showFormatList = 0;

    // 解析命令行参数
    if (argc < 2) {
        printHelp(argv[0]);
        return 1;
    }

    int argIdx = 1;
    while (argIdx < argc) {
        if (strcmp(argv[argIdx], "-h") == 0) {
            printHelp(argv[0]);
            return 0;
        } else if (strcmp(argv[argIdx], "-l") == 0) {
            showFormatList = 1;
            argIdx++;
        } else if (strcmp(argv[argIdx], "-f") == 0) {
            if (argIdx + 1 >= argc) {
                fprintf(stderr, "错误：-f 选项需要指定格式编号\n");
                printHelp(argv[0]);
                return 1;
            }
            format = (UnzipFormat)atoi(argv[argIdx + 1]);
            if (format < 0 || format >= sizeof(formatNames)/sizeof(formatNames[0])) {
                fprintf(stderr, "错误：无效的格式编号\n");
                printFormatList();
                return 1;
            }
            argIdx += 2;
        } else {
            // 非选项参数，视为输入文件和输出目录
            if (inputFile == NULL) {
                inputFile = argv[argIdx];
            } else if (outputDir == NULL) {
                outputDir = argv[argIdx];
            } else {
                fprintf(stderr, "错误：多余的参数 - %s\n", argv[argIdx]);
                printHelp(argv[0]);
                return 1;
            }
            argIdx++;
        }
    }

    // 如果只需要显示格式列表
    if (showFormatList) {
        printFormatList();
        return 0;
    }

    // 检查输入文件和输出目录是否提供
    if (inputFile == NULL || outputDir == NULL) {
        fprintf(stderr, "错误：请指定压缩文件路径和输出目录\n");
        printHelp(argv[0]);
        return 1;
    }

    // 检查输入文件是否存在
    if (!fileExists(inputFile)) {
        fprintf(stderr, "错误：输入文件不存在 - %s\n", inputFile);
        return 1;
    }

    // 创建输出目录
    if (!createDirectory(outputDir)) {
        fprintf(stderr, "错误：无法创建输出目录 - %s\n", outputDir);
        return 1;
    }

    // 加载DLL
    if (loadUnzipDLL("unzip.dll") != 0) {
        fprintf(stderr, "错误：无法加载解压引擎，确保unzip.dll在当前目录\n");
        return 1;
    }

    // 显示解压信息
    printf("压缩文件: %s\n", inputFile);
    printf("输出目录: %s\n", outputDir);
    printf("解压格式: %s\n", formatNames[format]);
    printf("开始解压...\n");

    // 记录开始时间
    clock_t start = clock();
    UnzipErrCode result;

    // 执行解压
    if (format == UNZIP_FORMAT_AUTO) {
        result = pUnzipFile((char*)inputFile, (char*)outputDir);
    } else {
        result = pUnzipFileWithFormat((char*)inputFile, (char*)outputDir, format);
    }

    // 计算耗时
    double elapsed = (double)(clock() - start) / CLOCKS_PER_SEC;

    // 处理结果
    if (result == UNZIP_OK) {
        printf("解压成功！耗时: %.2f秒\n", elapsed);
        printf("文件已解压至: %s\n", outputDir);
    } else {
        printError(result);
        freeUnzipDLL();
        return 1;
    }

    // 清理资源
    freeUnzipDLL();
    return 0;
}
